package com.micro.maven.plugin;

import cn.micro.core.util.StringUtil;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfoList;
import io.github.classgraph.ScanResult;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import java.util.*;
import java.util.stream.Collectors;

import cn.micro.core.util.JsonUtil;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.*;

import org.springframework.core.type.ClassMetadata;

import javax.xml.parsers.DocumentBuilderFactory;


@Mojo(name = "parse-rest-api",
        requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME,
        requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class RestApiParserMojo extends AbstractMojo {

    /**
     * Maven 项目对象
     */
    @Parameter(defaultValue = "${project}", readonly = true, required = true)
    private MavenProject project;

    /**
     * 编译后的 class 文件目录
     */
    @Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
    private File classesDirectory;

    /**
     * 接口信息输出文件（JSON 格式）
     */
    @Parameter(defaultValue = "${project.build.directory}/rest-api.json", required = true)
    private File outputFile;

    /**
     * 要扫描的基础包（可选，为空则扫描所有）
     */
    @Parameter
    private String basePackage;

    /**
     * Javassist 类池（解析参数名）
     */
    private final ClassPool classPool = ClassPool.getDefault();

    @Override
    public void execute() throws MojoExecutionException {
        getLog().info("=== 开始解析 RestController 接口 ===");
        getLog().info("classesDirectory: " + classesDirectory);
        getLog().info("outputFile: " + outputFile);
        try {
            // 2. 扫描并解析所有 RestController
            List<ControllerInfo> controllerList = scanRestControllers();

            getLog().info("========================================================");
            getLog().info("扫描完成！共扫描到 " + controllerList.size() + " 个 RestController，"
                    + "总计 " + controllerList.stream().mapToInt(c -> c.getApiList().size()).sum() + " 个接口"
            );
            getLog().info("========================================================");
        } catch (Throwable e) {
            getLog().error("扫描接口失败", e);
            throw new MojoExecutionException("接口扫描异常", e);
        } finally {
            getLog().info("=== 接口信息解析完毕 ===");
        }
    }

    // 来自 org.springframework.boot.maven.RunMojo
    private List<URL> getClassPathUrls() throws MojoExecutionException {
        List<URL> urls = new ArrayList<>();
        // 1. 添加应用编译类目录（优先加载）
        File classesDirectory = new File(this.project.getBuild().getOutputDirectory());
        if (classesDirectory.exists()) {
            urls.add(fileToUrl(classesDirectory));
        }
        // 2. 添加依赖 JAR（runtime 作用域）
        Set<Artifact> artifacts = getArtifacts(this.project);
        for (Artifact artifact : artifacts) {
            if (artifact.getFile() != null && artifact.getFile().exists()) {
                urls.add(fileToUrl(artifact.getFile()));
            }
        }
        // 3. 添加系统依赖
        for (Artifact artifact : this.project.getArtifacts()) {
            if (artifact.getScope() == Artifact.SCOPE_SYSTEM && artifact.getFile() != null) {
                urls.add(fileToUrl(artifact.getFile()));
            }
        }
        return urls;
    }

    /**
     * 从 MavenProject 中获取指定作用域（Scope）的依赖 Artifact 集合
     * 兼容 Maven 3.x，支持多 Scope 过滤，自动排除无效/不存在的 Artifact
     *
     * @param project       Maven 项目对象（插件中通过 @Parameter 注入）
     * @param includeScopes 需要包含的 Scope 列表（如 Arrays.asList("compile", "runtime")）
     * @return 符合条件的 Artifact 集合（已过滤掉 file 为 null/不存在的 Artifact）
     * @throws MojoExecutionException 当参数非法或解析依赖失败时抛出
     */
    public Set<Artifact> getArtifacts(MavenProject project, List<String> includeScopes) throws MojoExecutionException {
        // 1. 参数校验
        if (project == null) {
            throw new MojoExecutionException("MavenProject 不能为空！");
        }
        if (includeScopes == null || includeScopes.isEmpty()) {
            throw new MojoExecutionException("需要包含的 Scope 列表不能为空！");
        }

        // 2. 校验 Scope 合法性（避免传入无效 Scope）
        Set<String> validScopes = new HashSet<>(Arrays.asList(
                Artifact.SCOPE_COMPILE,
                Artifact.SCOPE_RUNTIME,
                Artifact.SCOPE_PROVIDED,
                Artifact.SCOPE_TEST,
                Artifact.SCOPE_SYSTEM,
                Artifact.SCOPE_IMPORT
        ));
        List<String> invalidScopes = includeScopes.stream()
                .filter(scope -> !validScopes.contains(scope))
                .collect(Collectors.toList());
        if (!invalidScopes.isEmpty()) {
            throw new MojoExecutionException("无效的 Scope 列表：" + invalidScopes + "，合法值：" + validScopes);
        }

        // 3. 获取项目所有依赖（直接依赖 + 传递依赖）
        Set<Artifact> allArtifacts = project.getArtifacts();
        getLog().info("项目总依赖数：" + allArtifacts.size());

        // 4. 按 Scope 过滤依赖（核心逻辑）
        Set<Artifact> filteredArtifacts = new LinkedHashSet<>(); // 保持依赖顺序
        for (Artifact artifact : allArtifacts) {
            String artifactScope = artifact.getScope();
            // 兼容 Scope 为 null 的情况（Maven 部分依赖默认 Scope 为 compile）
            if (artifactScope == null) {
                artifactScope = Artifact.SCOPE_COMPILE;
            }

            // 匹配目标 Scope
            if (includeScopes.contains(artifactScope)) {
                // 过滤掉 file 为 null/不存在的 Artifact（避免后续 URL 转换失败）
                if (artifact.getFile() != null && artifact.getFile().exists()) {
                    filteredArtifacts.add(artifact);
                    // 调试日志：打印关键依赖（如 zt3000）
                    if (artifact.getArtifactId().contains("zt3000") || artifact.getGroupId().contains("zt3000")) {
                        getLog().debug("✅ 匹配到 zt3000 依赖：" + artifact.getId() + " → " + artifact.getFile().getPath());
                    }
                } else {
                    getLog().warn("⚠️ 依赖文件不存在，跳过：" + artifact.getId() + "（Scope：" + artifactScope + "）");
                }
            }
        }

        // 5. 打印过滤结果
        getLog().info("按 Scope [" + String.join(",", includeScopes) + "] 过滤后，有效依赖数：" + filteredArtifacts.size());
        if (filteredArtifacts.isEmpty()) {
            getLog().warn("⚠️ 未找到符合条件的依赖，请检查 Scope 配置或项目依赖");
        }

        return filteredArtifacts;
    }

// ====================== 重载方法（简化调用）======================

    /**
     * 重载：仅获取 compile + runtime 作用域的依赖（最常用场景）
     */
    public Set<Artifact> getArtifacts(MavenProject project) throws MojoExecutionException {
        return getArtifacts(project, Arrays.asList(
                Artifact.SCOPE_COMPILE,
                Artifact.SCOPE_RUNTIME,
                Artifact.SCOPE_SYSTEM,
                Artifact.SCOPE_PROVIDED
        ));
    }

    /**
     * 重载：获取单个 Scope 的依赖
     */
    public Set<Artifact> getArtifacts(MavenProject project, String singleScope) throws MojoExecutionException {
        return getArtifacts(project, Collections.singletonList(singleScope));
    }

    // 工具方法：File → URL（处理 Windows 路径、空格等问题）
    private URL fileToUrl(File file) throws MojoExecutionException {
        try {
            return file.toURI().toURL();
        } catch (MalformedURLException ex) {
            throw new MojoExecutionException("Invalid file URL for " + file, ex);
        }
    }

    /**
     * 扫描所有 RestController 类
     */
    private List<ControllerInfo> scanRestControllers() throws Exception {
        // 构建目标项目类路径时，确保包含所有 compile 依赖
        List<String> fullClasspathElements = project.getCompileClasspathElements();
        if (fullClasspathElements == null || fullClasspathElements.isEmpty()) {
            throw new MojoFailureException("目标项目类路径为空！请先执行 mvn compile");
        }
        ClassLoader pluginClassLoader = Thread.currentThread().getContextClassLoader();
        List<URL> classpathUrls = new ArrayList<>(getClassPathUrls());
        ClassLoader projectClassLoader = new URLClassLoader(classpathUrls.toArray(new URL[0]), pluginClassLoader) {
            @Override
            protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
                Class<?> loadedClass = findLoadedClass(name);
                if (loadedClass == null) {
                    try {
                        // 优先从目标项目类路径加载
                        loadedClass = findClass(name);
                    } catch (ClassNotFoundException e) {
                        // 兜底从插件类加载器加载
                        loadedClass = super.loadClass(name, resolve);
                    }
                }
                if (resolve) resolveClass(loadedClass);
                return loadedClass;
            }
        };
        Thread.currentThread().setContextClassLoader(projectClassLoader);
        basePackage = StringUtil.isBlank(basePackage) ? "com.zt3000" : basePackage;
        // 1. 初始化类扫描器
        try (ScanResult scanResult = new ClassGraph()
                .addClassLoader(projectClassLoader)          // 指定class目录
                .acceptPackages(basePackage)       // 仅扫描指定包
                .enableAllInfo()                   // 启用所有信息（注解、方法、参数等）
                .ignoreClassVisibility()           // 忽略类访问权限
                .scan()) {
            ClassInfoList classInfos = scanResult.getClassesWithAllAnnotations(RestController.class, Controller.class);
            getLog().info("扫描到 " +classInfos.size() + " 个 RestController 类");
            classInfos.forEach(classInfo -> {
                getLog().info("扫描到 RestController 类：" + classInfo.getName());
            });
        } finally {

        }

        ClassPathScanningCandidateComponentProvider scanning = createScanner(projectClassLoader);
        scanning.addIncludeFilter(new AnnotationTypeFilter(RestController.class));
        scanning.addIncludeFilter(new AnnotationTypeFilter(Controller.class));
        List<ControllerInfo> controllerList = new ArrayList<>();
        Set<BeanDefinition> beanDefinitions = scanning.findCandidateComponents(basePackage);
        getLog().info("扫描到 " + beanDefinitions.size() + " 个 RestController 类");
        for (BeanDefinition beanDefinition : beanDefinitions) {
            Class<?> clazz = Class.forName(beanDefinition.getBeanClassName(), true, projectClassLoader);
            ControllerInfo controllerInfo = parseController(clazz);
            if (null != controllerInfo) {
                controllerList.add(controllerInfo);
            }
        }
        return controllerList;
    }

    // 修复版扫描器创建方法
    private ClassPathScanningCandidateComponentProvider createScanner(ClassLoader projectClassLoader) {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                ClassMetadata metadata = beanDefinition.getMetadata();
                return metadata.isConcrete() && !metadata.isInterface() && !metadata.hasEnclosingClass();
            }
        };
        // 三重绑定类加载器
        scanner.setResourceLoader(new DefaultResourceLoader(projectClassLoader));

        // 精准过滤规则：@RestController 或 @Controller+@ResponseBody
        scanner.addIncludeFilter((metadataReader, factory) -> {
            AnnotationMetadata am = metadataReader.getAnnotationMetadata();
            return am.hasAnnotation(RestController.class.getName())
                    || (am.hasAnnotation(Controller.class.getName()) && am.hasAnnotation(ResponseBody.class.getName()));
        });

        // 排除内部类/测试类
        scanner.addExcludeFilter((metadataReader, factory) -> {
            String className = metadataReader.getClassMetadata().getClassName();
            return className.contains("$") || className.endsWith("Test");
        });

        return scanner;
    }

    /**
     * 解析单个 Controller 信息
     */
    private ControllerInfo parseController(Class<?> controllerClass) throws Exception {
        try {
            ControllerInfo controllerInfo = new ControllerInfo();
            controllerInfo.setControllerName(controllerClass.getSimpleName());
            controllerInfo.setControllerFullName(controllerClass.getName());

            // 解析类级别基础路径
            String basePath = parseClassRequestMapping(controllerClass);
            controllerInfo.setBasePath(normalizePath(basePath));

            ReflectionUtils.doWithMethods(controllerClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    getLog().info("遍历解析接口: " + controllerClass.getName() + "." + method.getName());
                }
            }, this::hasRequestMappingAnnotation);

            // 解析所有接口方法
            List<ApiInfo> apiList = new ArrayList<>();
            for (Method method : controllerClass.getDeclaredMethods()) {
                // 过滤非接口方法（如私有方法、静态方法）
                if (Modifier.isPrivate(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
                    continue;
                }
                boolean hasRequestMapping = hasRequestMappingAnnotation(method);
                getLog().info("解析接口: " + controllerClass.getName() + "." + method.getName() + "parameters:" + (Arrays.toString(method.getParameters())) + "= >" + hasRequestMapping);
                // 解析带有 @RequestMapping 及其派生注解的方法
                if (hasRequestMapping) {
                    ApiInfo apiInfo = parseApiMethod(method, basePath);
                    apiList.add(apiInfo);
                }
            }
            controllerInfo.setApiList(apiList);

            return controllerInfo;
        } catch (Throwable e) {
            getLog().error("解析接口失败: " + controllerClass.getName(), e);
        }
        return null;
    }

    /**
     * 解析接口方法核心信息
     */
    private ApiInfo parseApiMethod(Method method, String basePath) throws Exception {
        ApiInfo apiInfo = new ApiInfo();

        // 1. 接口名称（方法名）
        apiInfo.setMethodName(method.getName());

        // 2. 接口完整路径
        String methodPath = parseMethodRequestMapping(method);
        apiInfo.setApiPath(normalizePath(basePath + "/" + methodPath));

        // 3. 请求方式（GET/POST/PUT/DELETE/ALL）
        Set<String> requestMethods = parseRequestMethods(method);
        apiInfo.setRequestMethods(requestMethods);

        // 4. 请求参数（名称、类型、注解）
        List<ParamInfo> paramList = parseMethodParams(method);
        apiInfo.setRequestParams(paramList);

        // 5. 返回参数（类型 + 泛型）
        ReturnInfo returnInfo = parseReturnInfo(method);
        apiInfo.setReturnParam(returnInfo);

        return apiInfo;
    }

    // ===================== 核心解析方法 =====================

    /**
     * 解析类级别 @RequestMapping 基础路径
     */
    private String parseClassRequestMapping(Class<?> clazz) {
        if (clazz.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping anno = clazz.getAnnotation(RequestMapping.class);
            return anno.value().length > 0 ? anno.value()[0] : "";
        }
        return "";
    }

    /**
     * 解析方法级别 @RequestMapping 路径
     */
    private String parseMethodRequestMapping(Method method) {
        if (method.isAnnotationPresent(RequestMapping.class)) {
            return getFirstValue(method.getAnnotation(RequestMapping.class).value());
        } else if (method.isAnnotationPresent(GetMapping.class)) {
            return getFirstValue(method.getAnnotation(GetMapping.class).value());
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            return getFirstValue(method.getAnnotation(PostMapping.class).value());
        } else if (method.isAnnotationPresent(PutMapping.class)) {
            return getFirstValue(method.getAnnotation(PutMapping.class).value());
        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
            return getFirstValue(method.getAnnotation(DeleteMapping.class).value());
        } else if (method.isAnnotationPresent(PatchMapping.class)) {
            return getFirstValue(method.getAnnotation(PatchMapping.class).value());
        }
        return "";
    }

    /**
     * 解析请求方法（GET/POST 等）
     */
    private Set<String> parseRequestMethods(Method method) {
        Set<String> methods = new HashSet<>();

        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMethod[] requestMethods = method.getAnnotation(RequestMapping.class).method();
            if (requestMethods.length == 0) {
                methods.add("ALL");
            } else {
                methods = Arrays.stream(requestMethods).map(RequestMethod::name).collect(Collectors.toSet());
            }
        } else if (method.isAnnotationPresent(GetMapping.class)) {
            methods.add("GET");
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            methods.add("POST");
        } else if (method.isAnnotationPresent(PutMapping.class)) {
            methods.add("PUT");
        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
            methods.add("DELETE");
        } else if (method.isAnnotationPresent(PatchMapping.class)) {
            methods.add("PATCH");
        }

        return methods;
    }

    /**
     * 解析请求参数（名称、类型、注解）
     */
    private List<ParamInfo> parseMethodParams(Method method) throws Exception {
        List<ParamInfo> paramList = new ArrayList<>();
        java.lang.reflect.Parameter[] parameters = method.getParameters();
        String[] paramNames = getParamNamesByJavassist(method); // 解析参数名（无需 -parameters）

        for (int i = 0; i < parameters.length; i++) {
            java.lang.reflect.Parameter param = parameters[i];
            ParamInfo paramInfo = new ParamInfo();

            // 参数名（优先 Javassist 解析，否则用 arg0/arg1）
            paramInfo.setParamName(paramNames != null && paramNames.length > i ? paramNames[i] : "arg" + i);
            // 参数类型（全类名）
            paramInfo.setParamType(param.getType().getName());
            // 参数注解（格式化展示）
            paramInfo.setParamAnnotations(parseParamAnnotations(param));

            paramList.add(paramInfo);
        }

        return paramList;
    }

    /**
     * 解析返回参数（类型 + 泛型）
     */
    private ReturnInfo parseReturnInfo(Method method) {
        ReturnInfo returnInfo = new ReturnInfo();

        // 原始返回类型
        Class<?> returnClass = method.getReturnType();
        returnInfo.setReturnType(returnClass.getName());
        returnInfo.setReturnSimpleName(returnClass.getSimpleName());

        // 泛型类型（如 ResponseEntity<UserVO> → UserVO）
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) genericReturnType;
            List<String> genericTypes = Arrays.stream(paramType.getActualTypeArguments())
                    .map(Type::getTypeName)
                    .collect(Collectors.toList());
            returnInfo.setGenericTypes(genericTypes);
        } else {
            returnInfo.setGenericTypes(Collections.emptyList());
        }

        return returnInfo;
    }

    // ===================== 工具方法 =====================

    /**
     * 用 Javassist 解析方法参数名（兼容无 -parameters 编译）
     */
    private String[] getParamNamesByJavassist(Method method) throws Exception {
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();

        CtClass ctClass = classPool.get(className);
        CtClass[] ctParamTypes = new CtClass[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            ctParamTypes[i] = classPool.get(paramTypes[i].getName());
        }

        try {
            CtMethod ctMethod = ctClass.getDeclaredMethod(methodName, ctParamTypes);
            MethodInfo methodInfo = ctMethod.getMethodInfo();
            CodeAttribute codeAttr = methodInfo.getCodeAttribute();
            if (codeAttr == null) return null;

            LocalVariableAttribute localVarAttr = (LocalVariableAttribute) codeAttr.getAttribute(LocalVariableAttribute.tag);
            if (localVarAttr == null) return null;

            // 静态方法参数从 0 开始，非静态方法第一个参数是 this（索引 0）
            int startIndex = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
            String[] paramNames = new String[ctMethod.getParameterTypes().length];
            for (int i = 0; i < paramNames.length; i++) {
                paramNames[i] = localVarAttr.variableName(i + startIndex);
            }
            return paramNames;
        } finally {
            ctClass.detach(); // 释放 CtClass
        }
    }

    /**
     * 解析参数注解（格式化展示）
     */
    private String parseParamAnnotations(java.lang.reflect.Parameter param) {
        List<String> annoList = new ArrayList<>();
        for (Annotation anno : param.getAnnotations()) {
            String annoName = anno.annotationType().getSimpleName();
            if (anno instanceof RequestParam) {
                RequestParam rp = (RequestParam) anno;
                annoList.add(String.format("@%s(value=\"%s\", required=%s)", annoName, rp.value(), rp.required()));
            } else if (anno instanceof PathVariable) {
                PathVariable pv = (PathVariable) anno;
                annoList.add(String.format("@%s(value=\"%s\", required=%s)", annoName, pv.value(), pv.required()));
            } else if (anno instanceof RequestBody) {
                RequestBody rb = (RequestBody) anno;
                annoList.add(String.format("@%s(required=%s)", annoName, rb.required()));
            } else if (anno instanceof RequestHeader) {
                RequestHeader rh = (RequestHeader) anno;
                annoList.add(String.format("@%s(value=\"%s\", required=%s)", annoName, rh.value(), rh.required()));
            } else {
                annoList.add("@" + annoName);
            }
        }
        return annoList.isEmpty() ? "无" : String.join(", ", annoList);
    }

    /**
     * 规范化路径（去重斜杠、处理末尾斜杠）
     */
    private String normalizePath(String path) {
        if (path == null) path = "";
        path = path.replaceAll("//+", "/"); // 去重斜杠
        if (path.endsWith("/") && path.length() > 1) {
            path = path.substring(0, path.length() - 1);
        }
        return path.isEmpty() ? "/" : path;
    }

    /**
     * 判断方法是否有 @RequestMapping 及其派生注解
     */
    private boolean hasRequestMappingAnnotation(Method method) {
        return AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class);
//        return method.isAnnotationPresent(RequestMapping.class) ||
//                method.isAnnotationPresent(GetMapping.class) ||
//                method.isAnnotationPresent(PostMapping.class) ||
//                method.isAnnotationPresent(PutMapping.class) ||
//                method.isAnnotationPresent(DeleteMapping.class) ||
//                method.isAnnotationPresent(PatchMapping.class);
    }

    /**
     * 判断类是否有 @ResponseBody 注解（兼容 @Controller + @ResponseBody 场景）
     */
    private boolean hasResponseBody(Class<?> clazz) {
        return clazz.isAnnotationPresent(ResponseBody.class) ||
                Arrays.stream(clazz.getMethods()).anyMatch(m -> m.isAnnotationPresent(ResponseBody.class));
    }

    /**
     * 获取注解 value 数组的第一个值（为空则返回空字符串）
     */
    private String getFirstValue(String[] values) {
        return values != null && values.length > 0 ? values[0] : "";
    }

    /**
     * 递归遍历 class 文件
     */
    private void traverseClassFiles(File rootDir, File currentDir, ClassFileHandler handler) throws Exception {
        File[] files = currentDir.listFiles();
        if (files == null) return;

        for (File file : files) {
            try {
                if (file.isDirectory()) {
                    traverseClassFiles(rootDir, file, handler);
                } else if (file.getName().endsWith(".class") && !file.getName().contains("$")) { // 排除内部类
                    String relativePath = file.getAbsolutePath().substring(rootDir.getAbsolutePath().length() + 1);
                    String className = relativePath.replace(File.separatorChar, '.').replace(".class", "");
                    handler.handle(file, className);
                }
            } catch (Throwable e) {
                // getLog().error("遍历文件出错：" + file.getAbsolutePath(), e);
            }
        }
    }

    // ===================== 控制台打印接口信息（核心） =====================
    private void printApiInfo(List<ControllerInfo> controllerList) {
        for (ControllerInfo controller : controllerList) {
            // 打印 Controller 标题
            getLog().info("\n=========================================");
            getLog().info("Controller: " + controller.getControllerName());
            getLog().info("全类名: " + controller.getControllerFullName());
            getLog().info("基础路径: " + controller.getBasePath());
            getLog().info("=========================================");

            // 打印该 Controller 下的所有接口
            List<ApiInfo> apiList = controller.getApiList();
            if (apiList.isEmpty()) {
                getLog().info("【无接口方法】");
                continue;
            }

            for (int i = 0; i < apiList.size(); i++) {
                ApiInfo api = apiList.get(i);
                getLog().info("\n【接口 " + (i + 1) + "】");
                getLog().info("方法名: " + api.getMethodName());
                getLog().info("接口地址: " + api.getApiPath());
                getLog().info("请求方式: " + String.join(", ", api.getRequestMethods()));

                // 打印请求参数
                getLog().info("请求参数: ");
                List<ParamInfo> params = api.getRequestParams();
                if (params.isEmpty()) {
                    getLog().info("  - 无参数");
                } else {
                    for (ParamInfo param : params) {
                        getLog().info(String.format("  - %s (%s) | 注解: %s",
                                param.getParamName(), param.getParamSimpleName(), param.getParamAnnotations()));
                    }
                }

                // 打印返回参数
                ReturnInfo returnInfo = api.getReturnParam();
                getLog().info("返回参数: ");
                getLog().info("  - 类型: " + returnInfo.getReturnSimpleName());
                if (!returnInfo.getGenericTypes().isEmpty()) {
                    getLog().info("  - 泛型: " + String.join(", ", returnInfo.getGenericTypes()));
                }
            }
        }
    }

    // ===================== 数据模型类 =====================
    // Controller 信息
    public static class ControllerInfo {
        private String controllerName;       // Controller 简单名
        private String controllerFullName;   // Controller 全类名
        private String basePath;             // 基础路径
        private List<ApiInfo> apiList;       // 接口列表

        // Getter & Setter
        public String getControllerName() {
            return controllerName;
        }

        public void setControllerName(String controllerName) {
            this.controllerName = controllerName;
        }

        public String getControllerFullName() {
            return controllerFullName;
        }

        public void setControllerFullName(String controllerFullName) {
            this.controllerFullName = controllerFullName;
        }

        public String getBasePath() {
            return basePath;
        }

        public void setBasePath(String basePath) {
            this.basePath = basePath;
        }

        public List<ApiInfo> getApiList() {
            return apiList;
        }

        public void setApiList(List<ApiInfo> apiList) {
            this.apiList = apiList;
        }
    }

    // 接口信息
    public static class ApiInfo {
        private String methodName;          // 方法名
        private String apiPath;             // 接口完整路径
        private Set<String> requestMethods; // 请求方式
        private List<ParamInfo> requestParams; // 请求参数
        private ReturnInfo returnParam;     // 返回参数

        // Getter & Setter
        public String getMethodName() {
            return methodName;
        }

        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }

        public String getApiPath() {
            return apiPath;
        }

        public void setApiPath(String apiPath) {
            this.apiPath = apiPath;
        }

        public Set<String> getRequestMethods() {
            return requestMethods;
        }

        public void setRequestMethods(Set<String> requestMethods) {
            this.requestMethods = requestMethods;
        }

        public List<ParamInfo> getRequestParams() {
            return requestParams;
        }

        public void setRequestParams(List<ParamInfo> requestParams) {
            this.requestParams = requestParams;
        }

        public ReturnInfo getReturnParam() {
            return returnParam;
        }

        public void setReturnParam(ReturnInfo returnParam) {
            this.returnParam = returnParam;
        }
    }

    // 参数信息
    public static class ParamInfo {
        private String paramName;           // 参数名
        private String paramType;           // 参数全类名
        private String paramAnnotations;    // 参数注解

        // 快捷获取参数简单类型名
        public String getParamSimpleName() {
            return paramType.substring(paramType.lastIndexOf(".") + 1);
        }

        // Getter & Setter
        public String getParamName() {
            return paramName;
        }

        public void setParamName(String paramName) {
            this.paramName = paramName;
        }

        public String getParamType() {
            return paramType;
        }

        public void setParamType(String paramType) {
            this.paramType = paramType;
        }

        public String getParamAnnotations() {
            return paramAnnotations;
        }

        public void setParamAnnotations(String paramAnnotations) {
            this.paramAnnotations = paramAnnotations;
        }
    }

    // 返回参数信息
    public static class ReturnInfo {
        private String returnType;          // 返回类型全类名
        private String returnSimpleName;    // 返回类型简单名
        private List<String> genericTypes;  // 泛型类型列表

        // Getter & Setter
        public String getReturnType() {
            return returnType;
        }

        public void setReturnType(String returnType) {
            this.returnType = returnType;
            this.returnSimpleName = returnType.substring(returnType.lastIndexOf(".") + 1);
        }

        public String getReturnSimpleName() {
            return returnSimpleName;
        }

        public void setReturnSimpleName(String returnSimpleName) {
            this.returnSimpleName = returnSimpleName;
        }

        public List<String> genericTypes() {
            return genericTypes;
        }

        public List<String> getGenericTypes() {
            return genericTypes;
        }

        public void setGenericTypes(List<String> genericTypes) {
            this.genericTypes = genericTypes;
        }
    }

    // 函数式接口：处理 class 文件
    @FunctionalInterface
    private interface ClassFileHandler {
        void handle(File file, String className) throws Exception;
    }

}
